import numpy as np
import matplotlib.pyplot as plt
from typing import Tuple, Optional

class Config:
    """导数计算配置"""
    WINDOW_SIZE = 10  # 滑动窗口大小
    PLOT_STYLE = {
        'figure_size': (10, 6),
        'line_width': 1.5,
        'title_size': 12,
        'label_size': 10
    }

def create_time_array(length: int, sampling_rate: float) -> np.ndarray:
    """创建时间数组
    
    Args:
        length: 数组长度
        sampling_rate: 采样率 (Hz)
        
    Returns:
        np.ndarray: 时间数组
    """
    time_step = 1 / sampling_rate
    return np.arange(length) * time_step

def fit_line(x: np.ndarray, y: np.ndarray) -> float:
    """使用线性拟合计算斜率
    
    Args:
        x: x轴数据
        y: y轴数据
        
    Returns:
        float: 拟合直线的斜率
    """
    coefficients = np.polyfit(x, y, 1)
    return coefficients[0]

def get_window_indices(index: int, array_length: int, window_size: int) -> Tuple[np.ndarray, np.ndarray]:
    """获取滑动窗口的索引
    
    Args:
        index: 当前位置
        array_length: 数组长度
        window_size: 窗口大小
        
    Returns:
        Tuple[np.ndarray, np.ndarray]: 窗口的x和y索引
    """
    if index < window_size:
        # 前向窗口
        start, end = 0, window_size
    elif index > array_length - window_size - 1:
        # 后向窗口
        start, end = array_length - window_size, array_length
    else:
        # 中心窗口
        start = index - window_size
        end = index + window_size
        
    return np.arange(start, end)

def calculate_deri(Vc: np.ndarray, Fs: float) -> np.ndarray:
    """通过滑动窗口拟合直线的斜率来计算导数 dVc/dt
    
    Args:
        Vc: Vc 数据数组
        Fs: 采样率 (Hz)
        
    Returns:
        np.ndarray: 与 Vc 长度一致的导数数组
    """
    time = create_time_array(len(Vc), Fs)
    dVc_dt = np.zeros_like(Vc)
    
    for i in range(len(Vc)):
        window_indices = get_window_indices(i, len(Vc), Config.WINDOW_SIZE)
        dVc_dt[i] = fit_line(time[window_indices], Vc[window_indices])
        
    return dVc_dt

def plot_derivative(Vc: np.ndarray, dVc_dt: np.ndarray,
                   Fs: float, title: Optional[str] = None) -> None:
    """绘制导数结果
    
    Args:
        Vc: 原始数据
        dVc_dt: 导数数据
        Fs: 采样率
        title: 图表标题（可选）
    """
    style = Config.PLOT_STYLE
    time = create_time_array(len(Vc), Fs)
    
    plt.figure(figsize=style['figure_size'])
    
    # 绘制原始数据
    plt.subplot(211)
    plt.plot(time * 1e6, Vc, linewidth=style['line_width'])
    plt.title('原始信号', fontsize=style['title_size'])
    plt.xlabel('时间 [μs]', fontsize=style['label_size'])
    plt.ylabel('幅度', fontsize=style['label_size'])
    
    # 绘制导数
    plt.subplot(212)
    plt.plot(time * 1e6, dVc_dt, linewidth=style['line_width'])
    plt.title(title or '导数', fontsize=style['title_size'])
    plt.xlabel('时间 [μs]', fontsize=style['label_size'])
    plt.ylabel('dVc/dt', fontsize=style['label_size'])
    
    plt.tight_layout()
    plt.show()

if __name__ == '__main__':
    # 测试代码
    # 生成示例数据
    t = np.linspace(0, 1, 1000)
    Vc = np.sin(2 * np.pi * 5 * t) * np.exp(-3 * t)
    Fs = 117.402e6 / 14
    
    # 计算导数
    dVc_dt = calculate_deri(Vc, Fs)
    
    # 绘制结果
    plot_derivative(Vc, dVc_dt, Fs, '基于拟合斜率的导数计算结果')
